package com.junjie.blibli.service.ElasticSearch;

import com.junjie.blibli.Entity.UserInfo;
import com.junjie.blibli.Entity.Video;
import com.junjie.blibli.dao.repository.UserInfoRepository;
import com.junjie.blibli.dao.repository.VideoRepository;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class ElasticSearchService {
    @Autowired
    private VideoRepository videoRepository;

    @Autowired
    private UserInfoRepository userInfoRepository;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    //添加视频到数据库
    public void addVideo(Video video){
        //这个方法是自带的，只需要继承一个类就行了，具体进接口里面看
        videoRepository.save(video);
    }

    //根据关键字查询数据库
    public Video getVideos(String keyWord){
        //跟jpa一样，可以直接用命名法去查询
        Video video = videoRepository.findByTitleLike(keyWord);
        return video;
    }

    //增加用户
    public void addUserInfo(UserInfo userInfo){
        userInfoRepository.save(userInfo);
    }

    public List<Map<String,Object>> getContent(String keyword,Integer pageNo,Integer pageSize) throws IOException {
        //ES提供的原生查询类SearchRequest
        //indices 是所有索引内容
        String[] indices = {"videos","user-infos"};
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //从0页开始
        sourceBuilder.from(pageNo-1);
        sourceBuilder.size(pageSize);
        //第二个形参是需要高亮的字段
        MultiMatchQueryBuilder matchQueryBuilder =
                QueryBuilders.multiMatchQuery(keyword,"title","nick","description");
        sourceBuilder.query(matchQueryBuilder);
        searchRequest.source(sourceBuilder);
        //超时时间
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //高亮显示 array存的是需要高亮的字段
        String[] array = {"title","nick","description"};
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        for (String key : array) highlightBuilder.fields().add(new HighlightBuilder.Field(key));
        //如果需要多个字段进行高亮，这个要置为false
        highlightBuilder.requireFieldMatch(false);
        //在高亮字段显示样式
        highlightBuilder.preTags("<span style=\"color:red\">");
        highlightBuilder.postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);

        //执行搜索，第二个参数是操作类型
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        List<Map<String,Object>> arrayList = new ArrayList<>();
        //hit就是匹配到的，查询出来的结果
        for (SearchHit hit : searchResponse.getHits()) {
            //处理高亮字段，先获取到高亮字段
            Map<String, HighlightField> highlightBuilderFields = hit.getHighlightFields();
            Map<String, Object> sourceMap = hit.getSourceAsMap();
            for (String key : array) {
                HighlightField field = highlightBuilderFields.get(key);
                if(field!=null){
                    Text[] fragments = field.fragments();
                    String str = Arrays.toString(fragments);
                    //减去头和尾的中括号
                    str = str.substring(1,str.length()-1);
                    //内容替换
                    sourceMap.put(key,str);
                }
            }
            arrayList.add(sourceMap);
        }
        return arrayList;
    }
}
